<script setup lang="ts">
import { onMounted, ref, Ref } from "vue";
import addImage from "../../../public/mxgraph/images/add.png";
import vueMxObject from "./mxVueGraphLoader";
import * as path from "path";

const {
    vueMxEvent,
    vueMxGraph,
    vueMxEditor,
    vueMxUtils,
    vueMxGraphHandler,
    vueMxConstants,
    vueMxCodec,
    vueMxRectangleShape,
    vueMxCellTracker,
    vueMxClient,
    vueMxPerimeter,
    vueMxEventObject,
    vueMxGeometry,
    vueMxCell,
    vueMxHierarchicalLayout,
    vueMxMorphing,
    vueMxEdgeHandler,
    vueMxCellState,
    vueMxShape,
    vueMxImage,
    vueMxCellOverlay,
    vueMxCellRenderer,
    vueMxRubberband,
    vueMxStencilRegistry,
    vueMxStencil,
    ActiveXObject
} = vueMxObject;

let palettes = {};
const graphEditorRef: Ref<HTMLDivElement | undefined> = ref();


function instanceGraph(graph, shapeItem, x, y, width, height) {
    const parent = graph.getDefaultParent()

    graph.getModel().beginUpdate()
    try {
        let vertex = graph.insertVertex(parent, null, null, x, y, width, height, `shape=${shapeItem['name']};`)

        vertex.customer = true
    } finally {
        graph.getModel().endUpdate()
    }
}


function createThumb(item, width, height) {
    const tmpGraph = new vueMxGraph(document.createElement('div'))
    const thumbBorder = 2

    tmpGraph.labelsVisible = false
    tmpGraph.view.scaleAndTranslate(1, 0, 0)

    instanceGraph(tmpGraph, item, 0, 0, width, height)

    const bounds = tmpGraph.getGraphBounds()
    const s = Math.floor(Math.min((width - 2 * thumbBorder) / bounds.width, (height - 2 * thumbBorder) / bounds.height) * 100) / 100

    tmpGraph.view.scaleAndTranslate(s, Math.floor((width - bounds.width * s) / 2 / s - bounds.x), Math.floor((height - bounds.height * s) / 2 / s - bounds.y))

    const node = tmpGraph.view.getCanvas().ownerSVGElement.cloneNode(true)

    node.style.position = 'relative'
    node.style.overflow = 'hidden'
    node.style.cursor = 'move'
    node.style.width = `${width}px`
    node.style.height = `${height}px`
    node.style.left = `${thumbBorder}px`
    node.style.top = `${thumbBorder}px`
    node.style.display = 'inline-block'
    return node
}
function initToolBar() {
    const domArray = this.$refs.dragItem

    if (!(domArray instanceof Array) || domArray.length <= 0 || this.R.isNil(this.graph)) {
        return
    }
    domArray.forEach(dom => {
        const shapeIndex = dom.getAttribute('shapeIndex')
        const paletteIndex = dom.getAttribute('paletteIndex')
        const shapeItem = palettes[paletteIndex]['shapes'][shapeIndex]
        const width = shapeItem['width']
        const height = shapeItem['height']
        const dragHandler = (graph, evt, cell, x, y) => {
            instanceGraph(this.graph, shapeItem, x, y, width, height)
        }
        const createDragPreview = () => {
            const elt = document.createElement('div')

            elt.style.border = '2px dotted black'
            elt.style.width = `${width}px`
            elt.style.height = `${height}px`
            return elt
        }
        dom.appendChild(createThumb(shapeItem, width, height))

        vueMxUtils.makeDraggable(dom, this.graph, dragHandler, createDragPreview(), 0, 0, false, true)
    })
}

function addStencilPalette(title: string, arrows: string, file: string) {
    let req = vueMxUtils.load(file)
    let root = req.getDocumentElement()
    let shape = root.firstChild

    this.$set(palettes, name, {title, name, shapes: []})

    while (shape != null) {
        if (shape.nodeType === vueMxConstants.NODETYPE_ELEMENT) {
            const shapeName = shape.getAttribute('name')
            const w = shape.getAttribute('w')
            const h = shape.getAttribute('h')

            vueMxStencilRegistry.addStencil(shapeName, new vueMxStencil(shape))
            palettes[name]['shapes'].push({name: shape.getAttribute('name'), width: w / 2, height: h / 2})
        }

        shape = shape.nextSibling
    }
}

onMounted(() => {
    console.log("11111111111111111111111111111111111111111A")
    if (graphEditorRef.value) {
        const container = graphEditorRef.value;
        console.log("11111111111111111111111111111111111111111B")
        init(container);
        console.log("init end!");
        addStencilPalette('箭头', 'arrows', path.join('./arrows.xml'))
        console.log("init toolbar!");
        this.$nextTick(() => {
            initToolBar()
        })
    }
});

const init = (container: HTMLDivElement) => {
    vueMxEvent.disableContextMenu(container);

    const mxCellRendererInstallCellOverlayListeners =
        vueMxCellRenderer.prototype.installCellOverlayListeners;

    vueMxCellRenderer.prototype.installCellOverlayListeners = function (
        state,
        overlay,
        shape
    ) {
        mxCellRendererInstallCellOverlayListeners.apply(vueMxCellRenderer, [
            state,
            overlay,
            shape,
        ]);

        vueMxEvent.addListener(
            shape.node,
            vueMxClient.IS_POINTER ? "pointerdown" : "mousedown",
            function (evt: Event) {
                overlay.fireEvent(
                    new vueMxEventObject(
                        "pointerdown",
                        "event",
                        evt,
                        "state",
                        state
                    ),
                    null
                );
            }
        );

        if (!vueMxClient.IS_POINTER && vueMxClient.IS_TOUCH) {
            vueMxEvent.addListener(
                shape.node,
                "touchstart",
                function (evt: Event) {
                    overlay.fireEvent(
                        new vueMxEventObject(
                            "pointerdown",
                            "event",
                            evt,
                            "state",
                            state
                        ),
                        null
                    );
                }
            );
        }
    };

    const graph = new vueMxGraph(container);
    console.log("current graph is now here!");
    //let currentGraph;
    //currentGraph.value = graph;
    console.log("current graph is end here!");

    graph.setPanning(true);
    graph.panningHandler.useLeftButtonForPanning = true;
    graph.setAllowDanglingEdges(false);
    graph.connectionHandler.select = false;
    graph.view.setTranslate(20, 20);
    console.log("11111111111111111111111111111C")
    const rubberBand = new vueMxRubberband(graph);

    const parent = graph.getDefaultParent();
    console.log("11111111111111111111111111111D")

    const addOverlay = function (cell) {
        const overlay = new vueMxCellOverlay(
            new vueMxImage(addImage, 24, 24),
            "Add outgoing"
        );

        overlay.cursor = "hand";

        overlay.addListener(vueMxEvent.CLICK, function (sender, evt2) {
            graph.clearSelection();
            const geo = graph.getCellGeometry(cell);
            let v2;

            executeLayout(
                function () {
                    v2 = graph.insertVertex(
                        parent,
                        null,
                        "World!",
                        geo.x,
                        geo.y,
                        80,
                        30
                    );
                    addOverlay(v2);
                    // graph.view.refresh(v2);
                    graph.view.refresh();
                    const el = graph.insertEdge(parent, null, "", cell, v2);
                },
                function () {
                    graph.scrollCellToVisible(v2);
                }
            );
        });

        overlay.addListener(
            "pointerdown",
            function (sender: any, eo) {
                const evt2 = eo.getProperty("event");
                const state = eo.getProperty("state");

                graph.popupMenuHandler.hideMenu();
                graph.stopEditing(false);

                const pt = vueMxUtils.convertPoint(
                    graph.container,
                    vueMxEvent.getClientX(evt2),
                    vueMxEvent.getClientY(evt2)
                );

                graph.connectionHandler.start(state, pt.x, pt.y);
                graph.isMouseDown = true;
                (graph as any).isMouseTrigger = vueMxEvent.isMouseEvent(evt2);

                vueMxEvent.consume(evt2);
            }
        );

        graph.addCellOverlay(cell, overlay);
    };

    const layout = new vueMxHierarchicalLayout(
        graph,
        vueMxConstants.DIRECTION_WEST
    );

    let v1;

    graph.getModel().beginUpdate();
    try {
        v1 = graph.insertVertex(parent, null, "Hello, ", 0, 0, 80, 30);
        addOverlay(v1);
    } finally {
        graph.getModel().endUpdate();
    }

    const executeLayout = function (change?: Function, post?: Function) {
        graph.getModel().beginUpdate();
        try {
            if (change != null) {
                change();
            }
            layout.execute(graph.getDefaultParent(), [v1]);
        } catch (e) {
            throw e;
        } finally {
            const morgh = new vueMxMorphing(graph);
            morgh.addListener(
                vueMxEvent.DONE,

                () => {
                    graph.getModel().endUpdate();

                    if (post != null) {
                        post();
                    }
                }
            );

            morgh.startAnimation();
        }
    };

    const edgeHandleConnect = vueMxEdgeHandler.prototype.connect;

    vueMxEdgeHandler.prototype.connect = function (
        edge,
        terminal,
        isSource,
        isClone,
        me
    ) {
        const cell = edgeHandleConnect.apply(vueMxEdgeHandler, [
            edge,
            terminal,
            isSource,
            isClone,
            me,
        ]);

        executeLayout();

        return cell;
    };

    graph.resizeCell = function (cell, bounds, recurse) {
        return vueMxGraph.prototype.resizeCell.apply(graph.resizeCell, [
            cell,
            bounds,
            recurse,
        ]);
    };

    graph.connectionHandler.addListener(vueMxEvent.CONNECT, function () {
        executeLayout();
    });
    console.log("11111111111111111111111111111E")

};
</script>

<template>
    <div class="stencilToolbarContainer">
        <div class="toolbarContainer">
            <el-collapse>
                <el-collapse-item v-for="(palette, paletteIndex) in palettes"
                                  :title="palette['title']"
                                  :name="palette['name']"
                                  :key="paletteIndex"
                >
                    <a v-for="(_, shapeIndex) in palette['shapes']"
                       :shapeIndex="shapeIndex"
                       :paletteIndex="paletteIndex"
                       ref="dragItem"
                       :key="shapeIndex"
                    >
                    </a>
                </el-collapse-item>
            </el-collapse>
        </div>
        <div class="graphContainer" tabindex="1" ref="graphEditorRef"></div>
    </div>
</template>
<style scoped>
.stencilToolbarContainer {
    width: 100%;
    height: 100%;
    display: flex;
    position: relative;

    .toolbarContainer {
        flex: 2;
        font-size: 20px;
        background: #efefef;
        text-align: center;
        overflow: auto;
    }

    .graphContainer {
        outline: none;
        position: relative;
        flex: 7;
    }
}
</style>
